import {
  CadScene,
  CSPoint,
  CSys,
  EventsRes,
  ICurve,
  MathTool,
  MouseInfo,
  SceneGraph,
  SceneSetup,
  SketchFrame,
} from '@amcax/base';
import { Picker2D, PickerMgr } from '@amcax/renderer';
import { ctx2 } from '@app-cad/module';

import { renderSketch } from '@app-cad/common/utils';
import { wsApi } from '@app-cad/server';
import { Vector2tuple, Vector3 } from 'three-legacy';

import { MessageTip } from '@app-cad/common/utils/MessageTip';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '../../../events/SketchEventCenter';
import { MouseState, State } from './types';

export class CmdInteractor {
  point: Vector3;
  currentState: MouseState = State.DRAW;
  // 草图数据
  public sketchData: ICurve[];
  protected exitFunc = () => {};
  private planeNormal: Vector3;
  private planeOrigin: Vector3;
  public faceCSys: CSys;
  public assisGroup: THREE.Object3D;
  private cadScene: CadScene;
  private sceneSetup: SceneSetup;
  public sketchFrame;
  private lastParams: string;
  private isFirstPointSet: boolean;
  private firstPoint: Vector2tuple;
  private lastPoint: Vector2tuple;
  private frame: number[][];
  private sketchId: string = sketchEventCenter().getSketchInfo().sketchId;
  protected picker = PickerMgr.getPicker<Picker2D>('2d');

  constructor() {
    this.frame = sketchEventCenter().getSketchInfo().frame;
    this.cadScene = ctx2.cadScene as CadScene;
    this.assisGroup = this.cadScene.assisGroup;

    this.sceneSetup = ctx2.viewer.sceneSetup;
    this.lastParams = '';
    this.sketchFrame = new SketchFrame(this.frame);
    this.faceCSys = MathTool.createCsysFromPlacement(this.frame);
    this.planeNormal = this.faceCSys.getNormalVc3();
    this.planeOrigin = this.faceCSys.getOriginVc3();
    this.firstPoint = null;
    this.lastPoint = null;
    this.isFirstPointSet = false;

    this.registerEvents();
  }

  public registerEvents() {
    sketchEventCenter()
      .setState('trim')
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onPointMove)
      .on(SKETCH_CENTEREVENTS.POINTERUP, this.onPointUp)
      .addExit(this.destory.bind(this));
  }

  public unregisterEvents() {
    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onPointMove)
      .off(SKETCH_CENTEREVENTS.POINTERUP, this.onPointUp)
      .setDefault();
  }

  destory() {
    // 移除约束
    this.reset();

    this.unregisterEvents();
    this.releaseObjects();
    SceneGraph.emptyGroup(this.assisGroup);
    this.exitFunc();
  }

  protected getPointByMouse(mouse: MouseInfo) {
    const mousePoint = this.sceneSetup.mouseOnPlane(
      mouse.x,
      mouse.y,
      this.planeNormal,
      this.planeOrigin,
    );
    return this.sketchFrame.toLocal(mousePoint);
  }

  public addExit(exitFunc: () => void) {
    this.exitFunc = exitFunc;
  }

  onPointMove = async (e: EventsRes) => {
    this.point = this.getPointByMouse(e.mouse).clone();
    this.picker.pick(e, { line: true });
  };

  onPointUp = async (e: EventsRes) => {
    if (e.button.onLeft) {
      const info = this.picker.pick(e, { line: true });
      let dividePoint: Vector2tuple[];
      if (info && info.type !== 'Circle' && info.type !== 'Ellipse') {
        dividePoint = [[this.point.x, this.point.y]];
        const res = await wsApi.divideSketchCurve(
          this.sketchId,
          info.id,
          dividePoint,
        );
        if (res) {
          await renderSketch(this.sketchId, res);
          this.exitFunc();
        }
      } else if ((info && info.type == 'Circle') || info.type === 'Ellipse') {
        const points: CSPoint = new CSPoint({
          vertex: this.point,
          pointType: 'endPoint',
        });
        points.hoverOn();
        points.setSize(8);
        if (!this.isFirstPointSet) {
          this.firstPoint = [points.positions[0], points.positions[1]];
          this.isFirstPointSet = true;
          MessageTip.warning('圆和椭圆做分割需要两个点');
        } else {
          this.lastPoint = [points.positions[0], points.positions[1]];
        }

        this.cadScene.assisGroup.add(points);
        if (this.firstPoint && this.lastPoint) {
          const CircledividePoint: Vector2tuple[] = [
            this.firstPoint,
            this.lastPoint,
          ];
          const res = await wsApi.divideSketchCurve(
            this.sketchId,
            info.id,
            CircledividePoint,
          );
          if (res) {
            await renderSketch(this.sketchId, res);
            this.exitFunc();
          }
        }
      }
    }
  };

  reset() {}

  releaseObjects() {
    this.assisGroup.clear();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  }
}
